#include "../../inc/skyImage.h"
#include "../../inc/skyFile.h"
#include "../../inc/skyUtils.h"
#include "../../inc/skyBuffer.h"
#ifdef _WIN_

//#include "../thirdParty/win32/libpng/png.h"

//
//#define  QGLOBAL_H        // defined for wophone
//#include "../thirdParty/win32/libjpeg/jpeglib.h"
//#undef   QGLOBAL_H

//#pragma comment(lib,".\\code\\xlib\\adapter\\thirdParty\\win32\\libraries\\libjpeg.lib")
//#pragma comment(lib,".\\code\\xlib\\adapter\\thirdParty\\win32\\libraries\\libpng.lib")
//#pragma comment(lib,".\\code\\xlib\\adapter\\thirdParty\\win32\\libraries\\libzlib.lib")


namespace Sky
{

	typedef struct
	{
		unsigned int height;
		unsigned int width;
		int         bitsPerComponent;
		bool        hasAlpha;
		bool        isPremultipliedAlpha;
		unsigned char*  data;
	} tImageInfo;

	static unsigned int nextPOT(unsigned int x)
	{
		x = x - 1;
		x = x | (x >> 1);
		x = x | (x >> 2);
		x = x | (x >> 4);
		x = x | (x >> 8);
		x = x | (x >> 16);
		return x + 1;
	}

	

	#define CC_RGB_PREMULTIPLY_APLHA(vr, vg, vb, va) \
		(unsigned)(((unsigned)((unsigned char)(vr) * ((unsigned char)(va) + 1)) >> 8) | \
		((unsigned)((unsigned char)(vg) * ((unsigned char)(va) + 1) >> 8) << 8) | \
		((unsigned)((unsigned char)(vb) * ((unsigned char)(va) + 1) >> 8) << 16) | \
		((unsigned)(unsigned char)(va) << 24))

	typedef struct 
	{
		unsigned char* data;
		int size;
		int offset;
	}tImageSource;

	//static void pngReadCallback(png_structp png_ptr, png_bytep data, png_size_t length)
	//{
	//	tImageSource* isource = (tImageSource*)png_get_io_ptr(png_ptr);

	//	if((int)(isource->offset + length) <= isource->size)
	//	{
	//		memcpy(data, isource->data+isource->offset, length);
	//		isource->offset += length;
	//	}
	//	else
	//	{
	//		png_error(png_ptr, "pngReaderCallback failed");
	//	}
	//}

	

	//////////////////////////////////////////////////////////////////////////
	// Impliment Image
	//////////////////////////////////////////////////////////////////////////

	Image::Image()
	: m_nWidth(0)
	, m_nHeight(0)
	, m_nBitsPerComponent(0)
	, m_pData(0)
	, m_bHasAlpha(false)
	, m_bPreMulti(false)
	{

	}

	Image::~Image()
	{
		SAFE_DELETE(m_pData);
	}

	//bool Image::createWithImageFile(String * strPath, EImageFormat eImgFmt/* = eFmtPng*/)
	//{
	//	do 
	//	{
	//		File data;
	//		E_Break_If(vFalse == data.open(Utils::fullPathFromRelativePath(*strPath), File::modeRead));
	//		i32 len = data.getLength();
	//		Buffer buff(len);
	//		E_Break_If(-1 == data.read(buff.getBuffer(),len));
	//		E_Break_If(vFalse == createWithImageData(buff.getBuffer(), buff.getSize(), eImgFmt));
	//		m_pData = buff.getBuffer();
	//		buff.incRef();
	//		return vTrue;

	//	} while (0);

	//	return vFalse;
	//}

	//bool Image::createWithImageData(void * pData, 
	//								int nDataLen, 
	//								EImageFormat eFmt/* = eSrcFmtPng*/, 
	//								int nWidth/* = 0*/,
	//								int nHeight/* = 0*/,
	//								int nBitsPerComponent/* = 8*/)
	//{
	//	bool bRet = false;
	//	do 
	//	{
	//		E_Break_If(! pData || nDataLen <= 0);

	//		if (FmtPng == eFmt)
	//		{
	//			bRet = _initWithPngData(pData, nDataLen);
	//			break;
	//		}
	//		else if (FmtJpg == eFmt)
	//		{
	//			bRet = _initWithJpgData(pData, nDataLen);
	//			break;
	//		}
	//		else if (FmtRawData == eFmt)
	//		{
	//			bRet = _initWithRawData(pData, nDataLen, nWidth, nHeight, nBitsPerComponent);
	//			break;
	//		}
	//	} while (0);
	//	return bRet;
	//}

	//bool Image::_initWithJpgData(void * data, int nSize)
	//{
	//	/* these are standard libjpeg structures for reading(decompression) */
	//	struct jpeg_decompress_struct cinfo;
	//	struct jpeg_error_mgr jerr;
	//	/* libjpeg data structure for storing one row, that is, scanline of an image */
	//	JSAMPROW row_pointer[1] = {0};
	//	unsigned long location = 0;
	//	unsigned int i = 0;

	//	bool bRet = false;
	//	do 
	//	{
	//		/* here we set up the standard libjpeg error handler */
	//		cinfo.err = jpeg_std_error( &jerr );

	//		/* setup decompression process and source, then read JPEG header */
	//		jpeg_create_decompress( &cinfo );

	//		/* this makes the library read from infile */
	//		jpeg_mem_src( &cinfo, (unsigned char *) data, nSize );

	//		/* reading the image header which contains image information */
	//		jpeg_read_header( &cinfo, true );

	//		// we only support RGB or grayscale
	//		if (cinfo.jpeg_color_space != JCS_RGB)
	//		{
	//			if (cinfo.jpeg_color_space == JCS_GRAYSCALE || cinfo.jpeg_color_space == JCS_YCbCr)
	//			{
	//				cinfo.out_color_space = JCS_RGB;
	//			}
	//		}
	//		else
	//		{
	//			break;
	//		}

	//		/* Start decompression jpeg here */
	//		jpeg_start_decompress( &cinfo );

	//		/* init image info */
	//		m_nWidth  = (short)(cinfo.image_width);
	//		m_nHeight = (short)(cinfo.image_height);
	//		m_bHasAlpha = false;
	//		m_bPreMulti = false;
	//		m_nBitsPerComponent = 8;
	//		row_pointer[0] = new unsigned char[cinfo.output_width*cinfo.output_components];
	//		E_Break_If(! row_pointer[0]);

	//		m_pData = new unsigned char[cinfo.output_width*cinfo.output_height*cinfo.output_components];
	//		E_Break_If(! m_pData);

	//		/* now actually read the jpeg into the raw buffer */
	//		/* read one scan line at a time */
	//		while( cinfo.output_scanline < cinfo.image_height )
	//		{
	//			jpeg_read_scanlines( &cinfo, row_pointer, 1 );
	//			for( i=0; i<cinfo.image_width*cinfo.num_components;i++) 
	//				m_pData[location++] = row_pointer[0][i];
	//		}

	//		jpeg_finish_decompress( &cinfo );
	//		jpeg_destroy_decompress( &cinfo );
	//		/* wrap up decompression, destroy objects, free pointers and close open files */        
	//		bRet = true;
	//	} while (0);

	//	SAFE_DELETE_ARRAY(row_pointer[0]);
	//	return bRet;
	//}

	//bool Image::_initWithPngData(void * pData, int nDatalen)
	//{
	//	bool bRet = false;
	//	png_byte        header[8]   = {0}; 
	//	png_structp     png_ptr     =   0;
	//	png_infop       info_ptr    = 0;
	//	unsigned char * pImateData  = 0;

	//	do 
	//	{
	//		// png header len is 8 bytes
 //   		E_Break_If(nDatalen < 8);

	//		// check the data is png or not
	//		memcpy(header, pData, 8);
	//		E_Break_If(png_sig_cmp(header, 0, 8));

	//		// init png_struct
	//		png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
	//		E_Break_If(! png_ptr);

	//		// init png_info
	//		info_ptr = png_create_info_struct(png_ptr);
	//		E_Break_If(!info_ptr || setjmp(png_jmpbuf(png_ptr)));

	//		// set the read call back function
	//		tImageSource imageSource;
	//		imageSource.data    = (unsigned char*)pData;
	//		imageSource.size    = nDatalen;
	//		imageSource.offset  = 0;
	//		png_set_read_fn(png_ptr, &imageSource, pngReadCallback);

	//		// read png
	//		// PNG_TRANSFORM_EXPAND: perform set_expand()
	//		// PNG_TRANSFORM_PACKING: expand 1, 2 and 4-bit samples to bytes
	//		// PNG_TRANSFORM_STRIP_16: strip 16-bit samples to 8 bits
	//		// PNG_TRANSFORM_GRAY_TO_RGB: expand grayscale samples to RGB (or GA to RGBA)
	//		png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_EXPAND | PNG_TRANSFORM_PACKING 
	//			| PNG_TRANSFORM_STRIP_16 | PNG_TRANSFORM_GRAY_TO_RGB, 0);

	//		int         color_type  = 0;
	//		png_uint_32 nWidth = 0;
	//		png_uint_32 nHeight = 0;
	//		int         nBitsPerComponent = 0;
	//		png_get_IHDR(png_ptr, info_ptr, &nWidth, &nHeight, &nBitsPerComponent, &color_type, 0, 0, 0);

	//		// init image info
	//		m_bPreMulti = true;
	//		m_bHasAlpha = ( info_ptr->color_type & PNG_COLOR_MASK_ALPHA ) ? true : false;

	//		// allocate memory and read data
	//		int bytesPerComponent = 3;
	//		if (m_bHasAlpha)
	//		{
	//			bytesPerComponent = 4;
	//		}
	//		pImateData = new unsigned char[nHeight * nWidth * bytesPerComponent];
	//		if(! pImateData)
	//			return vFalse;

	//		png_bytep * rowPointers = png_get_rows(png_ptr, info_ptr);

	//		// copy data to image info
	//		int bytesPerRow = nWidth * bytesPerComponent;
	//		if(m_bHasAlpha)
	//		{
	//			unsigned int *tmp = (unsigned int *)pImateData;
	//			for(unsigned int i = 0; i < nHeight; i++)
	//			{
	//				for(int j = 0; j < bytesPerRow; j += 4)
	//				{
	//					*tmp++ = CC_RGB_PREMULTIPLY_APLHA( rowPointers[i][j], rowPointers[i][j + 1], 
	//						rowPointers[i][j + 2], rowPointers[i][j + 3] );
	//				}
	//			}
	//		}
	//		else
	//		{
	//			for (unsigned int j = 0; j < nHeight; ++j)
	//			{
	//				memcpy(pImateData + j * bytesPerRow, rowPointers[j], bytesPerRow);
	//			}
	//		}

	//		m_nBitsPerComponent = nBitsPerComponent;
	//		m_nHeight   = (short)nHeight;
	//		m_nWidth    = (short)nWidth;
	//		m_pData     = pImateData;
	//		pImateData  = 0;
	//		bRet        = true;
	//	} while (0);

	//	SAFE_DELETE_ARRAY(pImateData);

	//	if (png_ptr)
	//	{
	//		png_destroy_read_struct(&png_ptr, (info_ptr) ? &info_ptr : 0, 0);
	//	}
	//	return bRet;
	//}

	bool Image::_initWithRawData(void * pData, int nDatalen, int nWidth, int nHeight, int nBitsPerComponent)
	{
		bool bRet = false;
		do 
		{
			E_Break_If(!nWidth || !nHeight);

			m_nBitsPerComponent = nBitsPerComponent;
			m_nHeight   = (short)nHeight;
			m_nWidth    = (short)nWidth;
			m_bHasAlpha = true;

			// only RGBA8888 surported
			int nBytesPerComponent = 4;
			int nSize = nHeight * nWidth * nBytesPerComponent;
			m_pData = new unsigned char[nSize];
			if(! m_pData)
				return bRet;
			memcpy(m_pData, pData, nSize);

			bRet = true;
		} while (0);
		return bRet;
	}

	bool Image::saveToFile(const Char *pszFilePath, bool bIsToRGB)
	{
		bool bRet = false;

		do 
		{
			if(!pszFilePath)
				return vFalse;

			String strFilePath(pszFilePath);
			if(strFilePath.getLength() <= 4)
				return vFalse;

			String strLowerCasePath(strFilePath);

			strLowerCasePath.toLower();

			if (strLowerCasePath->endWith(String(_XC(".png"))))
			{
				if(!_saveImageToPNG(pszFilePath, bIsToRGB))
					return vFalse;
			}
			else if (strLowerCasePath->endWith(String(_XC(".jpg"))))
			{
				if(!_saveImageToJPG(pszFilePath))
					return vFalse;
			}
			else
			{
				break;
			}

			bRet = true;
		} while (0);

		return bRet;
	}

	bool Image::_saveImageToPNG(const Char * pszFilePath, bool bIsToRGB)
	{
		bool bRet = false;
		/*String path(pszFilePath);
		
		do 
		{
			E_Break_If(NULL == pszFilePath);

			FILE *fp;
			png_structp png_ptr;
			png_infop info_ptr;
			png_colorp palette;
			png_bytep *row_pointers;

			fp = fopen(path.toCharString(), "wb");
			if(NULL == fp)
				return vFalse;

			png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);

			if (NULL == png_ptr)
			{
				fclose(fp);
				break;
			}

			info_ptr = png_create_info_struct(png_ptr);
			if (NULL == info_ptr)
			{
				fclose(fp);
				png_destroy_write_struct(&png_ptr, NULL);
				break;
			}

			if (setjmp(png_jmpbuf(png_ptr)))
			{
				fclose(fp);
				png_destroy_write_struct(&png_ptr, &info_ptr);
				break;
			}

			png_init_io(png_ptr, fp);

			if (!bIsToRGB && m_bHasAlpha)
			{
				png_set_IHDR(png_ptr, info_ptr, m_nWidth, m_nHeight, 8, PNG_COLOR_TYPE_RGB_ALPHA,
					PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
			} 
			else
			{
				png_set_IHDR(png_ptr, info_ptr, m_nWidth, m_nHeight, 8, PNG_COLOR_TYPE_RGB,
					PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
			}

			palette = (png_colorp)png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH * sizeof (png_color));
			png_set_PLTE(png_ptr, info_ptr, palette, PNG_MAX_PALETTE_LENGTH);

			png_write_info(png_ptr, info_ptr);

			png_set_packing(png_ptr);

			row_pointers = (png_bytep *)malloc(m_nHeight * sizeof(png_bytep));
			if(row_pointers == NULL)
			{
				fclose(fp);
				png_destroy_write_struct(&png_ptr, &info_ptr);
				break;
			}

			if (!m_bHasAlpha)
			{
				for (int i = 0; i < (int)m_nHeight; i++)
				{
					row_pointers[i] = (png_bytep)m_pData + i * m_nWidth * 3;
				}

				png_write_image(png_ptr, row_pointers);

				free(row_pointers);
				row_pointers = NULL;
			}
			else
			{
				if (bIsToRGB)
				{
					unsigned char *pTempData = new unsigned char[m_nWidth * m_nHeight * 3];
					if (NULL == pTempData)
					{
						fclose(fp);
						png_destroy_write_struct(&png_ptr, &info_ptr);
						break;
					}

					for (int i = 0; i < m_nHeight; ++i)
					{
						for (int j = 0; j < m_nWidth; ++j)
						{
							pTempData[(i * m_nWidth + j) * 3] = m_pData[(i * m_nWidth + j) * 4];
							pTempData[(i * m_nWidth + j) * 3 + 1] = m_pData[(i * m_nWidth + j) * 4 + 1];
							pTempData[(i * m_nWidth + j) * 3 + 2] = m_pData[(i * m_nWidth + j) * 4 + 2];
						}
					}

					for (int i = 0; i < (int)m_nHeight; i++)
					{
						row_pointers[i] = (png_bytep)pTempData + i * m_nWidth * 3;
					}

					png_write_image(png_ptr, row_pointers);

					free(row_pointers);
					row_pointers = NULL;

					SAFE_DELETE_ARRAY(pTempData);
				} 
				else
				{
					for (int i = 0; i < (int)m_nHeight; i++)
					{
						row_pointers[i] = (png_bytep)m_pData + i * m_nWidth * 4;
					}

					png_write_image(png_ptr, row_pointers);

					free(row_pointers);
					row_pointers = NULL;
				}
			}

			png_write_end(png_ptr, info_ptr);

			png_free(png_ptr, palette);
			palette = NULL;

			png_destroy_write_struct(&png_ptr, &info_ptr);

			fclose(fp);

			bRet = true;
		} while (0);*/
		return bRet;
	}
	bool Image::_saveImageToJPG(const Char * pszFilePath)
	{
		bool bRet = false;
		//do 
		//{
		//	E_Break_If(NULL == pszFilePath);

		//	struct jpeg_compress_struct cinfo;
		//	struct jpeg_error_mgr jerr;
		//	FILE * outfile;                 /* target file */
		//	JSAMPROW row_pointer[1];        /* pointer to JSAMPLE row[s] */
		//	int     row_stride;          /* physical row width in image buffer */

		//	cinfo.err = jpeg_std_error(&jerr);
		//	/* Now we can initialize the JPEG compression object. */
		//	jpeg_create_compress(&cinfo);

		//	if((outfile = fopen(pszFilePath, "wb")) == NULL)
		//		return vFalse;
		//	
		//	jpeg_stdio_dest(&cinfo, outfile);

		//	cinfo.image_width = m_nWidth;    /* image width and height, in pixels */
		//	cinfo.image_height = m_nHeight;
		//	cinfo.input_components = 3;       /* # of color components per pixel */
		//	cinfo.in_color_space = JCS_RGB;       /* colorspace of input image */

		//	jpeg_set_defaults(&cinfo);

		//	jpeg_start_compress(&cinfo, TRUE);

		//	row_stride = m_nWidth * 3; /* JSAMPLEs per row in image_buffer */

		//	if (m_bHasAlpha)
		//	{
		//		unsigned char *pTempData = new unsigned char[m_nWidth * m_nHeight * 3];
		//		if (NULL == pTempData)
		//		{
		//			jpeg_finish_compress(&cinfo);
		//			jpeg_destroy_compress(&cinfo);
		//			fclose(outfile);
		//			break;
		//		}

		//		for (int i = 0; i < m_nHeight; ++i)
		//		{
		//			for (int j = 0; j < m_nWidth; ++j)
		//			{
		//				pTempData[(i * m_nWidth + j) * 3] = m_pData[(i * m_nWidth + j) * 4];
		//				pTempData[(i * m_nWidth + j) * 3 + 1] = m_pData[(i * m_nWidth + j) * 4 + 1];
		//				pTempData[(i * m_nWidth + j) * 3 + 2] = m_pData[(i * m_nWidth + j) * 4 + 2];
		//			}
		//		}

		//		while (cinfo.next_scanline < cinfo.image_height) {
		//			row_pointer[0] = & pTempData[cinfo.next_scanline * row_stride];
		//			(void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
		//		}

		//		SAFE_DELETE_ARRAY(pTempData);
		//	} 
		//	else
		//	{
		//		while (cinfo.next_scanline < cinfo.image_height) {
		//			row_pointer[0] = & m_pData[cinfo.next_scanline * row_stride];
		//			(void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
		//		}
		//	}

		//	jpeg_finish_compress(&cinfo);
		//	fclose(outfile);
		//	jpeg_destroy_compress(&cinfo);
		//	
		//	bRet = true;
		//} while (0);
		return bRet;
	}


	/**
	@brief	A memory DC which uses to draw text on bitmap.
	*/
	class BitmapDC
	{
	public:
		BitmapDC(HWND hWnd = NULL)
			: m_hDC(NULL)
			, m_hBmp(NULL)
			, m_hFont((HFONT)GetStockObject(DEFAULT_GUI_FONT))
			, m_hWnd(NULL)
		{
			m_hWnd = hWnd;
			HDC hdc = GetDC(hWnd);
			m_hDC   = CreateCompatibleDC(hdc);
			ReleaseDC(hWnd, hdc);
		}

		~BitmapDC()
		{
			prepareBitmap(0, 0);
			if (m_hDC)
			{
				DeleteDC(m_hDC);
			}
			HFONT hDefFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
			if (hDefFont != m_hFont)
			{
				DeleteObject(m_hFont);
				m_hFont = hDefFont;
			}
			// release temp font resource	
			if (m_curFontPath.getLength() > 0)
			{
				/*wchar_t * pwszBuffer = utf8ToUtf16(m_curFontPath.toCharString(),m_curFontPath.getLength());
				if (pwszBuffer)*/
				{
					RemoveFontResource(m_curFontPath.toCharString());
					SendMessage( m_hWnd, WM_FONTCHANGE, 0, 0);
					//delete [] pwszBuffer;
					//pwszBuffer = NULL;
				}
			}
		}

		wchar_t * utf8ToUtf16(AChar* nString,i32 nLen)
		{
			wchar_t * pwszBuffer = NULL;
			do 
			{
				int nBufLen  = nLen + 1;			
				pwszBuffer = new wchar_t[nBufLen];
				E_Break_If(! pwszBuffer);
				memset(pwszBuffer,0,nBufLen);
				nLen = MultiByteToWideChar(CP_UTF8, 0, nString, nLen, pwszBuffer, nBufLen);		
				pwszBuffer[nLen] = '\0';
			} while (0);	
			return pwszBuffer;

		}

		bool setFont(HFONT font/*Char * pFontName = NULL, int nSize = 0*/)
		{
			m_hFont = font;
			return true;
			//bool bRet = false;
			//do 
			//{
			//	String fontName(pFontName);
			//	StringPtr fontPath;
			//	HFONT       hDefFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
			//	LOGFONTA    tNewFont = {0};
			//	LOGFONTA    tOldFont = {0};
			//	GetObject(hDefFont, sizeof(tNewFont), &tNewFont);
			//	if (fontName.toCharString())
			//	{	
			//		// create font from ttf file
			//		if (fontName.endWith(String(_XT(".TTF"))) || fontName.endWith(String(_XT(".ttf"))))
			//		{
			//			fontPath = Utils::fullPathFromRelativePath(fontName);
			//			i32 nFindPos = fontName.rFind(String(_XT("/")));
			//			//fontName = nFindPos + 1;
			//			nFindPos = fontName->rFind(String(_XT(".")));
			//			fontPath = fontName.subStr(0,nFindPos);				
			//		}
			//		tNewFont.lfCharSet = DEFAULT_CHARSET;
			//		memcpy(tNewFont.lfFaceName, fontPath->toCharString(),LF_FACESIZE * sizeof(Char));
			//	}
			//	if (nSize)
			//	{
			//		tNewFont.lfHeight = -nSize;
			//	}
			//	GetObject(m_hFont,  sizeof(tOldFont), &tOldFont);

			//	if (tOldFont.lfHeight == tNewFont.lfHeight
			//		&& ! strcpy(tOldFont.lfFaceName, tNewFont.lfFaceName))
			//	{
			//		// already has the font 
			//		bRet = true;
			//		break;
			//	}

			//	// delete old font
			//	if (m_hFont != hDefFont)
			//	{
			//		DeleteObject(m_hFont);
			//		// release old font register
			//		if (m_curFontPath.getLength() > 0)
			//		{
			//			/*wchar_t * pwszBuffer = utf8ToUtf16(m_curFontPath);
			//			if (pwszBuffer)*/
			//			{
			//				if(RemoveFontResource(m_curFontPath->toCharString()))
			//				{
			//					SendMessage( m_hWnd, WM_FONTCHANGE, 0, 0);
			//				}						
			//				/*delete [] pwszBuffer;
			//				pwszBuffer = NULL;*/
			//			}
			//		}
			//		fontPath->getLength()>0?(m_curFontPath.cloneFrom(fontPath)):(m_curFontPath.clear());
			//		// register temp font
			//		if (m_curFontPath.getLength() > 0)
			//		{
			//			/*wchar_t * pwszBuffer = utf8ToUtf16(m_curFontPath);
			//			if (pwszBuffer)*/
			//			{
			//				if(AddFontResource(m_curFontPath.toCharString()))
			//				{
			//					SendMessage( m_hWnd, WM_FONTCHANGE, 0, 0);
			//				}						
			//				/*delete [] pwszBuffer;
			//				pwszBuffer = NULL;*/
			//			}
			//		}
			//	}
			//	m_hFont = NULL;

			//	// create new font
			//	m_hFont = CreateFontIndirectA(&tNewFont);
			//	if (! m_hFont)
			//	{
			//		// create failed, use default font
			//		m_hFont = hDefFont;
			//		break;
			//	}

			//	bRet = true;
			//} while (0);
			//return bRet;
		}

		SIZE sizeWithText(const Char * pszText, int nLen, DWORD dwFmt, LONG nWidthLimit)
		{
			SIZE tRet = {0};
			do 
			{
				E_Break_If(! pszText || nLen <= 0);

				RECT rc = {0, 0, 0, 0};
				DWORD dwCalcFmt = DT_CALCRECT;

				if (nWidthLimit > 0)
				{
					rc.right = nWidthLimit;
					dwCalcFmt |= DT_WORDBREAK
						| (dwFmt & DT_CENTER)
						| (dwFmt & DT_RIGHT);
				}
				// use current font to measure text extent
				HGDIOBJ hOld = SelectObject(m_hDC, m_hFont);

				// measure text size
				DrawText(m_hDC, pszText, nLen, &rc, dwCalcFmt);
				SelectObject(m_hDC, hOld);

				tRet.cx = rc.right;
				tRet.cy = rc.bottom;
			} while (0);

			return tRet;
		}

		bool prepareBitmap(int nWidth, int nHeight)
		{
			// release bitmap
			if (m_hBmp)
			{
				DeleteObject(m_hBmp);
				m_hBmp = NULL;
			}
			if (nWidth > 0 && nHeight > 0)
			{
				m_hBmp = CreateBitmap(nWidth, nHeight, 1, 32, NULL);
				if (! m_hBmp)
				{
					return false;
				}
			}
			return true;
		}

		int drawText(const Char * pszText, SIZE& tSize, Sky::Color color,Image::ETextAlign eAlign)
		{

			int nRet = 0;
			wchar_t * pwszBuffer = 0;
			do 
			{
				E_Break_If(!pszText);

				DWORD dwFmt = DT_WORDBREAK;
				DWORD dwHoriFlag = eAlign & 0x0f;
				DWORD dwVertFlag = (eAlign & 0xf0) >> 4;

				switch (dwHoriFlag)
				{
				case 1: // left
					dwFmt |= DT_LEFT;
					break;
				case 2: // right
					dwFmt |= DT_RIGHT;
					break;
				case 3: // center
					dwFmt |= DT_CENTER;
					break;
				}

				int nLen = (int)skyStrlen(pszText);
				SIZE newSize = sizeWithText(pszText, nLen, dwFmt, tSize.cx);

				RECT rcText = {0};
				// if content width is 0, use text size as content size
				if (tSize.cx <= 0)
				{
					tSize = newSize;
					rcText.right  = newSize.cx;
					rcText.bottom = newSize.cy;
				}
				else
				{

					LONG offsetX = 0;
					LONG offsetY = 0;
					rcText.right = newSize.cx; // store the text width to rectangle

					// calculate text horizontal offset
					if (1 != dwHoriFlag          // and text isn't align to left
						&& newSize.cx < tSize.cx)   // and text's width less then content width,
					{                               // then need adjust offset of X.
						offsetX = (2 == dwHoriFlag) ? tSize.cx - newSize.cx     // align to right
							: (tSize.cx - newSize.cx) / 2;                      // align to center
					}

					// if content height is 0, use text height as content height
					// else if content height less than text height, use content height to draw text
					if (tSize.cy <= 0)
					{
						tSize.cy = newSize.cy;
						dwFmt   |= DT_NOCLIP;
						rcText.bottom = newSize.cy; // store the text height to rectangle
					}
					else if (tSize.cy < newSize.cy)
					{
						// content height larger than text height need, clip text to rect
						rcText.bottom = tSize.cy;
					}
					else
					{
						rcText.bottom = newSize.cy; // store the text height to rectangle

						// content larger than text, need adjust vertical position
						dwFmt |= DT_NOCLIP;

						// calculate text vertical offset
						offsetY = (2 == dwVertFlag) ? tSize.cy - newSize.cy     // align to bottom
							: (3 == dwVertFlag) ? (tSize.cy - newSize.cy) / 2   // align to middle
							: 0;                                                // align to top
					}

					if (offsetX || offsetY)
					{
						OffsetRect(&rcText, offsetX, offsetY);
					}
				}

				E_Break_If(! prepareBitmap(tSize.cx, tSize.cy));

				// draw text
				HGDIOBJ hOldFont = SelectObject(m_hDC, m_hFont);
				HGDIOBJ hOldBmp  = SelectObject(m_hDC, m_hBmp);

				SetBkMode(m_hDC, TRANSPARENT);
				SetTextColor(m_hDC, RGB(color.r, color.g, color.b)); // white color

				// utf-8 to utf-16
				int nBufLen  = nLen + 1;
				pwszBuffer = new wchar_t[nBufLen];
				E_Break_If(! pwszBuffer);
				//nLen = MultiByteToWideChar(CP_UTF8, 0, pszText, nLen, pwszBuffer, nBufLen);

				// draw text
				nRet = DrawText(m_hDC, pszText, -1, &rcText, dwFmt);

				//DrawTextA(m_hDC, pszText, nLen, &rcText, dwFmt);

				SelectObject(m_hDC, hOldBmp);
				SelectObject(m_hDC, hOldFont);
			} while (0);
			SAFE_DELETE_ARRAY(pwszBuffer);
			return nRet;
		}

		GetProperty(DC,HDC, m_hDC);
		GetProperty(Bitmap,HBITMAP, m_hBmp);
	private:
		friend class CCImage;
		HFONT   m_hFont;
		HWND	m_hWnd;
		String m_curFontPath;
	};

	static BitmapDC& sharedBitmapDC()
	{
		static BitmapDC s_BmpDC;
		return s_BmpDC;
	}

	bool Image::createWithString(
		Char *    pText, 
		Sky::Color color,
		Sky::Font*	   pFont,
		ETextAlign      eAlignMask/* = kAlignCenter*/)
	{
		bool bRet = false;
		unsigned char * pImageData = 0;
		i32 nSize = pFont ? pFont ->getWeight() : 0;
		Char* pFontName = pFont && pFont->getName() ? pFont->getName()->toCharString(): 0;
		i32 nWidth = 0;
		i32 nHeight = 0;
		SAFE_DELETE_ARRAY(m_pData);
		do 
		{
			E_Break_If(! pText);       

			BitmapDC& dc = sharedBitmapDC();

			if (! dc.setFont(pFont->getFont()))
			{
				xInfor1(_XT("Can't found font(%s), use system default"), pFontName);
			}

			// draw text
			SIZE size = {nWidth, nHeight};
			E_Break_If(! dc.drawText(pText, size,color, eAlignMask));

			pImageData = (unsigned char*)Memory::alloc(size.cx * size.cy * 4);
			E_Break_If(! pImageData);

			struct
			{
				BITMAPINFOHEADER bmiHeader;
				int mask[4];
			} bi = {0};
			bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
			E_Break_If(! GetDIBits(dc.getDC(), dc.getBitmap(), 0, 0, NULL, (LPBITMAPINFO)&bi, DIB_RGB_COLORS));

			m_nWidth    = (short)size.cx;
			m_nHeight   = (short)size.cy;
			m_bHasAlpha = true;
			m_bPreMulti = false;
			m_pData     = pImageData;
			pImageData  = 0;
			m_nBitsPerComponent = 8;
			// copy pixed data
			bi.bmiHeader.biHeight = (bi.bmiHeader.biHeight > 0)
				? - bi.bmiHeader.biHeight : bi.bmiHeader.biHeight;
			GetDIBits(dc.getDC(), dc.getBitmap(), 0, m_nHeight, m_pData, 
				(LPBITMAPINFO)&bi, DIB_RGB_COLORS);

			// change pixel's alpha value to 255, when it's RGB != 0
			COLORREF * pPixel = NULL;
			for (int y = 0; y < m_nHeight; ++y)
			{
				pPixel = (COLORREF *)m_pData + y * m_nWidth;
				for (int x = 0; x < m_nWidth; ++x)
				{
					COLORREF& clr = *pPixel;
					if (GetRValue(clr) || GetGValue(clr) || GetBValue(clr))
					{
						clr |= 0xff000000;
					}
					++pPixel;
				}
			}

			bRet = true;
		} while (0);

		return bRet;
	}

}

#endif
